package control;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import abstractGA.GAParameter;
import foundation.fileUtil.TxtFileUtil;
import foundation.pcmUtil.AllocationModelHelper;
import foundation.pcmUtil.RepositoryModelHelper;
import foundation.pcmUtil.ResEnvirExtFileHelper;
import foundation.pcmUtil.ResEnvirModelHelper;
import foundation.pcmUtil.RptFileHelper;
import foundation.pcmUtil.SystemModelHelper;

public class ExeCtx {
	protected String srcPath = null; // 源各模型文件存储路径
	protected String runBasePath = null;// 执行环境的基路径
	protected String caseName = null;// 案例名
	protected String sysMdlFlNm = null;// system模型位置
	protected String reposMdlFlNm = null;// 库模型位置
	protected String rescMdlFlNm = null;// 资源环境图存放位置
	protected String alloMdlFlNm = null;// 分配图存放位置
	protected String usageScenarioProer = null;// 性能报告响应时间所在的Processor
	protected String perfRptFlNm = null;// 性能评估报告文件名
	protected String reltRptFlNm = null;// 可靠性报告文件名

	SASolver saSolver = SASolver.getInstance();// SA解析器
	protected SystemModelHelper systemModelHelper = null;
	protected RepositoryModelHelper repositoryModelHelper = null;
	protected AllocationModelHelper allocationModelHelper = null;
	protected ResEnvirModelHelper resEnvirModelHelper = null;
	protected ResEnvirExtFileHelper resEnvirExtFileHelper = null;

	protected RptFileHelper perfRptHlper = null;// 性能报告助手类
	protected File reltRptFile = null;// 可靠性报告助手类
	// 算法配置文件名
	protected String algCfgFileName = null;
	// 自由度实例的编码
	protected List<StringBuffer> curFdCodes = new ArrayList<StringBuffer>();
	ArrayList<Integer> strtIdxs = new ArrayList<Integer>();// 处理器速度、组件部署和组件选择的起始下标
	protected GAParameter para = null;// 算法参数类
	protected boolean useMLearn = false;// 是否使用机器学习
	protected int sampleNum = 400;// 采样的样本数， 在求解真值状态下，采得样本数超过该值就触发机器学习;
	protected int predictNum = 14 * 30 * 20;// 预测次数，超过该次数需要求解真值
	// 获取初始SA信息的操作接口
	ISAMdlInfo saInfo = null;
	// 服务器名列表
	protected ArrayList<String> serverNames = new ArrayList<String>();
	// 可选组件名列表的列表（因可有多个组件都有一组可选的具体组件）
	protected ArrayList<ArrayList<String>> selCompNmLst = new ArrayList<ArrayList<String>>();

	/**
	 * @param srcPath:源各模型文件存储路径
	 * @param basePath:控制引擎执行需要一组文件的基路径
	 * @param caseName:案例名
	 */
	public ExeCtx(String srcPath, String basePath, String caseName,String algCfgFileName) {
		this.srcPath = srcPath;
		this.runBasePath = basePath;
		this.caseName = caseName;
		sysMdlFlNm = basePath + caseName.trim() + ".system";
		reposMdlFlNm = basePath + caseName.trim() + ".repository";
		rescMdlFlNm = basePath + caseName.trim() + ".resourceenvironment";
		alloMdlFlNm = basePath + caseName.trim() + ".allocation";
		this.algCfgFileName = algCfgFileName;
		////////////////////
		para = new GAParameter(algCfgFileName);
		useMLearn = para.isNeedSurModel();
		sampleNum = para.getSampleNum();
		predictNum = para.getPredictNum();
		// serverNames=getServerNames();
	}

	/**
	 * 根据服务器编号获取服务器名字,注意服务器编号从1开始， 服务器名字列表中下标为（服务器编号-1）的元素对应该编号的服务器名
	 * 
	 * @param serverNo：服务器编号
	 * @return
	 */
	public String getServerName(int serverNo) {
		String serverNm = null;
		if (serverNames.size() == 0) {
			serverNames = saInfo.getServerNames();
		}
		if (serverNo <= serverNames.size()) {
			serverNm = serverNames.get(serverNo - 1);
		}
		return serverNm;
	}

	/**
	 * 根据服务器名字获取对应的编号
	 * 
	 * @param serverNm：服务器名字
	 * @return
	 */
	public int getServerNo(String serverNm) {
		int serverNo = -1;
		if (serverNames.size() == 0) {
			serverNames = saInfo.getServerNames();
		}
		int size = serverNames.size();
		for (int i = 0; i < size; i++) {
			String curSvrNm = serverNames.get(i);
			if (serverNm.equals(curSvrNm)) {
				serverNo = i + 1;
				break;
			}
		}
		return serverNo;
	}

	/**
	 * 根据编码中特定可选组件位及在组件列表中的编号，返回组件名称
	 * 
	 * @param idx:在编码中的下标位置
	 * @param selCompNo：可选组件在列表中的编号，注意组件编号从1开始
	 * @return
	 */
	public String getSelCompName(int idx, int selCompNo) {
		String compNm = null;
		if (selCompNmLst.size() == 0) {
			selCompNmLst = saInfo.getSelCompNmList();
		}
		int strtPos = strtIdxs.get(2);
		if (idx >= strtPos && idx < curFdCodes.size()) {
			ArrayList<String> selCompNms = selCompNmLst.get(idx - strtPos);
			compNm = selCompNms.get(selCompNo - 1);
		}
		return compNm;
	}

	/**
	 * 根据编码中特定可选组件位及组件名称，返回组件编号，注意组件编号从1开始
	 * 
	 * @param selCompNm：被选择组件的名字
	 * @return
	 */
	public int getSelCompNo(int idx, String selCompNm) {
		int compNo = -1;
		if (selCompNmLst.size() == 0) {
			selCompNmLst = saInfo.getSelCompNmList();
		}
		int strtPos = strtIdxs.get(2);
		if (idx >= strtPos && idx < curFdCodes.size()) {
			ArrayList<String> selCompNms = selCompNmLst.get(idx - strtPos);
			int len = selCompNms.size();
			for (int i = 0; i < len; i++) {
				String curCompNm = selCompNms.get(i);
				if (curCompNm.equals(selCompNm)) {
					compNo = i + 1;
					break;
				}
			}
		}
		return compNo;
	}

	public void setNewMldHlper() {
		systemModelHelper = new SystemModelHelper(sysMdlFlNm);
		repositoryModelHelper = new RepositoryModelHelper(reposMdlFlNm);
		allocationModelHelper = new AllocationModelHelper(alloMdlFlNm);
		resEnvirModelHelper = new ResEnvirModelHelper(rescMdlFlNm);
		// 可靠性报告文件
		reltRptFile = new File(reltRptFlNm);
	}

	/**
	 * 将已打开的各模型文件和报告文件关闭， 再与新的上下文中的对应文件进行关联并打开
	 */
	public void freshMldHlper() {
		closeFiles();
		setNewMldHlper();
	}

	public void closeFiles() {
		// 刷新模型文件
		if (systemModelHelper != null) {
			systemModelHelper.close();
			systemModelHelper = null;
		}
		if (repositoryModelHelper != null) {
			repositoryModelHelper.close();
			repositoryModelHelper = null;
		}
		if (allocationModelHelper != null) {
			allocationModelHelper.close();
			allocationModelHelper = null;
		}
		if (resEnvirModelHelper != null) {
			resEnvirModelHelper.close();
			resEnvirModelHelper = null;
		}
		if (perfRptHlper != null) {// 关闭上次打开的性能评估报告文件
			perfRptHlper.closeNoSave();
			perfRptHlper = null;
		}
		// 可靠性报告文件
		if (reltRptFile != null) {
			reltRptFile = null;
		}

	}

	public void setInitExeCtx(List<StringBuffer> initFdCodes) {
		this.curFdCodes = initFdCodes;
//		TxtFileUtil.deleteFile(runBasePath, ".lqxo");
		// TxtFileUtil.delAllFile(runBasePath);
		if (!srcPath.equals(runBasePath)) {
			TxtFileUtil.copyFolder(srcPath, runBasePath);
		}
		freshMldHlper();
	}

	/**
	 * 此方法仅在初始上下文构建好后，方可调用
	 * 
	 * @param newFdCodes
	 */
	public void setCurFdCodes(List<StringBuffer> newFdCodes) {//
		boolean needUpdate = false;
		int curSize = curFdCodes.size();
		int newSize = newFdCodes.size();
		if (curSize == newSize) {
			for (int i = 0; i < curSize; i++) {
				String curCode = curFdCodes.get(i).toString();
				String newCode = newFdCodes.get(i).toString();
				if (!curCode.equals(newCode)) {
					needUpdate = true;
					break;
				}
			}
		}
		if (needUpdate) {// 更新的自由度编码与当前的相等，则不更新上下文中的文件
			this.curFdCodes = newFdCodes;
			setNewMldHlper();
		}
	}

	/**
	 * @param dfCodes:自由度编码（处理器为浮点型字符串，组件部署为服务器名字字符串，组件选择为组件名字符串）
	 * @return 机器学习的输入编码（处理器为浮点型字符串，组件部署为服务器编号字符串，组件选择为组件编号字符串）
	 */
	public List<StringBuffer> toMLDfcodes() {
		List<StringBuffer> mlFdCodes = new ArrayList<StringBuffer>();
		for (int j = strtIdxs.get(0); j < strtIdxs.get(1); j++) {// 添加处理速度
			mlFdCodes.add(curFdCodes.get(j));
		}
		for (int j = strtIdxs.get(1); j < strtIdxs.get(2); j++) {// 添加部署组件服务器编号
			String srvName = curFdCodes.get(j).toString();
			int srvNo = getServerNo(srvName);
			StringBuffer srvNoStrBf = new StringBuffer(String.valueOf(srvNo));
			mlFdCodes.add(srvNoStrBf);
		}
		for (int j = strtIdxs.get(2); j < curFdCodes.size(); j++) {// 添加选择组件编号
			String curCompName = curFdCodes.get(j).toString();
			int compNo = getSelCompNo(j, curCompName);
			StringBuffer compNoStrBf = new StringBuffer(String.valueOf(compNo));
			mlFdCodes.add(compNoStrBf);
		}
		return mlFdCodes;
	}

	/**
	 * 将机器学习编码转换成自由度实例列表
	 * 
	 * @param mlDfCodes:机器学习的编码
	 * @param strtIdxs:各种自由度的起始下标的列表
	 * @return
	 */
	public List<StringBuffer> ml2DfCodes(List<StringBuffer> mlDfCodes) {
		List<StringBuffer> dfCodes = new ArrayList<>();
		for (int j = strtIdxs.get(0); j < strtIdxs.get(1); j++) {// 添加处理速度
			dfCodes.add(mlDfCodes.get(j));
		}
		for (int j = strtIdxs.get(1); j < strtIdxs.get(2); j++) {// 添加部署组件服务器名字
			String srvNoStr = mlDfCodes.get(j).toString();
			String srvName = getServerName(Integer.parseInt(srvNoStr));
			StringBuffer srvNoStrBf = new StringBuffer(srvName);
			dfCodes.add(srvNoStrBf);
		}
		for (int j = strtIdxs.get(2); j < mlDfCodes.size(); j++) {// 添加选择的组件
			String compNoStr = mlDfCodes.get(j).toString();
			String compName = getSelCompName(j, Integer.parseInt(compNoStr));
			StringBuffer compNoStrBf = new StringBuffer(compName);
			dfCodes.add(compNoStrBf);
		}
		return dfCodes;
	}

	public String getRunBasePath() {
		return runBasePath;
	}

	public void setRunBasePath(String runBasePath) {
		this.runBasePath = runBasePath;
	}

	public String getCaseName() {
		return caseName;
	}

	public void setCaseName(String caseName) {
		this.caseName = caseName;
	}

	public String getSysMdlFlNm() {
		return sysMdlFlNm;
	}

	public void setSysMdlFlNm(String sysMdlFlNm) {
		this.sysMdlFlNm = sysMdlFlNm;
	}

	public String getReposMdlFlNm() {
		return reposMdlFlNm;
	}

	public void setReposMdlFlNm(String reposMdlFlNm) {
		this.reposMdlFlNm = reposMdlFlNm;
	}

	public String getRescMdlFlNm() {
		return rescMdlFlNm;
	}

	public void setRescMdlFlNm(String rescMdlFlNm) {
		this.rescMdlFlNm = rescMdlFlNm;
	}

	public String getAlloMdlFlNm() {
		return alloMdlFlNm;
	}

	public void setAlloMdlFlNm(String alloMdlFlNm) {
		this.alloMdlFlNm = alloMdlFlNm;
	}

	public String getPerfRptFlNm() {
		return perfRptFlNm;
	}

	public void setPerfRptFlNm(String perfRptFlNm) {
		this.perfRptFlNm = perfRptFlNm;
	}

	public String getUsageScenarioProer() {
		return usageScenarioProer;
	}

	public void setUsageScenarioProer(String usageScenarioProer1) {
		this.usageScenarioProer = usageScenarioProer1;
	}

	public String getReltRptFlNm() {
		return reltRptFlNm;
	}

	public void setReltRptFlNm(String reltRptFlNm) {
		this.reltRptFlNm = reltRptFlNm;
	}

	public List<StringBuffer> getCurFdCodes() {
		return curFdCodes;
	}

	public boolean isUseMLearn() {
		return useMLearn;
	}

	public void setUseMLearn(boolean useMLearn) {
		this.useMLearn = useMLearn;
	}

	public int getSampleNum() {
		return sampleNum;
	}

	public void setSampleNum(int sampleNum) {
		this.sampleNum = sampleNum;
	}

	public int getPredictNum() {
		return predictNum;
	}

	public void setPredictNum(int predictNum) {
		this.predictNum = predictNum;
	}

	public ArrayList<Integer> getStrtIdxs() {
		return strtIdxs;
	}

	public void setStrtIdxs(ArrayList<Integer> strtIdxs) {
		this.strtIdxs = strtIdxs;
	}

	public GAParameter getPara() {
		return para;
	}

	public void setPara(GAParameter para) {
		this.para = para;
	}

	public SASolver getSaSolver() {
		return saSolver;
	}

	public void setSaSolver(SASolver saSolver) {
		this.saSolver = saSolver;
	}

	public File getReltRptFile() {
		return reltRptFile;
	}

	public void setReltRptFile(File reltRptFile) {
		this.reltRptFile = reltRptFile;
	}

	public RptFileHelper getPerfRptHlper() {
		ArrayList<String> fileNms = TxtFileUtil.findFileNms(runBasePath, ".out.lqxo");
		int size = fileNms.size();
		perfRptFlNm = runBasePath + fileNms.get(size - 1);
		perfRptHlper = new RptFileHelper(perfRptFlNm);
		return perfRptHlper;
	}

	public void setPerfRptHlper(RptFileHelper perfRptHlper) {
		this.perfRptHlper = perfRptHlper;
	}

	public SystemModelHelper getSystemModelHelper() {
		return systemModelHelper;
	}

	public void setSystemModelHelper(SystemModelHelper systemModelHelper) {
		this.systemModelHelper = systemModelHelper;
	}

	public RepositoryModelHelper getRepositoryModelHelper() {
		return repositoryModelHelper;
	}

	public void setRepositoryModelHelper(RepositoryModelHelper repositoryModelHelper) {
		this.repositoryModelHelper = repositoryModelHelper;
	}

	public AllocationModelHelper getAllocationModelHelper() {
		return allocationModelHelper;
	}

	public void setAllocationModelHelper(AllocationModelHelper allocationModelHelper) {
		this.allocationModelHelper = allocationModelHelper;
	}

	public ISAMdlInfo getSaInfo() {
		return saInfo;
	}

	public void setSaInfo(ISAMdlInfo saInfo) {
		this.saInfo = saInfo;
	}

	public ArrayList<String> getServerNames() {
		if (serverNames.size() == 0) {
			serverNames = saInfo.getServerNames();
		}
		return serverNames;
	}

	public void setServerNames(ArrayList<String> serverNames) {
		this.serverNames = serverNames;
	}

	public ResEnvirExtFileHelper getResEnvirExtFileHelper() {
		return resEnvirExtFileHelper;
	}

	public void setResEnvirExtFileHelper(ResEnvirExtFileHelper resEnvirExtFileHelper) {
		this.resEnvirExtFileHelper = resEnvirExtFileHelper;
	}

}
